#include <iostream>
#include <list>
#include<algorithm>
#include <cstring>
using namespace std;

namespace Piece
{
    //定义颜色
    const bool Red = 1, Black = 0;
    const int DRAW = 3, CONTINUE = 4;

    class ChineseBoard;
    class ChinesePiece;

    //坐标点类
    class Point
    {
    protected:
        
        friend class ChineseBoard;
        friend class ChinesePiece;
        friend bool operator==(const Point &p1, const Point &p2);
    public:
        int x, y;
        Point(int x, int y):x(x), y(y){}
        const bool ColorOfArea() const
        {
            if(y<=4)
                return Red;
            else
                return Black;
        }
        const bool IsInTheNine() const
        {
            return x >= 3 &&  x <= 5 && (y <= 2 || y >= 7);
        }
        
        
    };

    //判断位置相等
    bool operator==(const Point &p1, const Point &p2)
    {
        return p1.x == p2.x && p1.y == p2.y;
    }

    //棋盘类
    class ChineseBoard
    {
    private:
        friend class ChinesePiece;
        //红色为0-4， 黑色为5-9
        ChinesePiece * board[10][9];
        std::list<ChinesePiece *> RED, BLACK;

    public:
        ChineseBoard();

        const std::list<ChinesePiece*>& GetRedPieces()const
        {
            return RED;
        }
        const std::list<ChinesePiece*>& GetBlackPieces()const
        {
            return BLACK;
        }

        ChinesePiece*& GetChess(const Point &point)
        {
            return board[point.y][point.x];
        }

        ChinesePiece* const& GetChess(const Point &point) const
        {
            return board[point.y][point.x];
        }
    
        void RemovePiece(const Point &point);
        bool KingFaceToFace();
        ~ChineseBoard();

    };

    //棋子基类
    class ChinesePiece
    {
    protected:
        Point point;
        ChineseBoard &board;
        
    public:
        const bool color;
        ChinesePiece(const Point &point, bool color, ChineseBoard &chineseboard):point(point), color(color), board(chineseboard) 
        {
            if(color == Red)
            {
                board.RED.push_back(this);
            }
            else
            {
                board.BLACK.push_back(this);
            }
            board.GetChess(point) = this;
        }

        Point &GetPoint()
        {
            return point;
        }

        //判断是否可以移动
        virtual bool CanMoveTo(const Point &po) = 0;
        //判断是否可以过河
        virtual const bool CanCrossRiver()const = 0;
        //判断是否在九宫格内
        virtual const char * GetName() = 0;

        //判断移动
        bool MoveTo(const Point &point)
        {
            //判断是否可以移动过去
            if(CanMoveTo(point))
            {   
                //当前位置为空
                board.GetChess(this->point) = nullptr;
                this->point.x = point.x;
                this->point.y = point.y;
                //如果目的地有对方棋子，吃掉
                board.RemovePiece(point);
                //位置换为当前棋子
                board.GetChess(point) = this;
                return true;
            }
            return false;
        }
        ~ChinesePiece(){}

    };

    //棋盘吃子
    void ChineseBoard::RemovePiece(const Point &point)
    {
        if(GetChess(point))
        {
            if(GetChess(point)->color == Red)
            {
                RED.erase(std::find(RED.begin(), RED.end(), GetChess(point)));
            }
            else
            {
                BLACK.erase(std::find(BLACK.begin(), BLACK.end(), GetChess(point)));
            }
            delete GetChess(point);
            GetChess(point) = nullptr;
        }
    }

    //车Rook
    class Rook:public ChinesePiece
    {
    public:
        Rook(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            //判断目的地为空或者目的地为对方棋子
            if(board.GetChess(po) == nullptr || board.GetChess(po)->color != this->color)
            {
                //判断中间是否有棋子挡住
                if(po.x == point.x)
                {
                    if(po.y > point.y)
                    {
                        for(int i = po.y-1; i != point.y; --i)
                        {
                            if(board.GetChess(Point(point.x, i)))
                                return false;
                        }
                    }
                    else
                    {
                        for(int i = po.y+1; i != point.y; ++i)
                        {
                            if(board.GetChess(Point(point.x, i)))
                                return false;
                        }
                    }

                    return true;
                }
                else if(po.y == point.y)
                {
                    if(po.x > point.x)
                    {
                        for(int i = po.x-1; i != point.x; --i)
                        {
                            if(board.GetChess(Point(i, point.y)))
                                return false;
                        }
                    }
                    else
                    {
                        for(int i = po.x+1; i != point.x; ++i)
                        {
                            if(board.GetChess(Point(i, point.y)))
                                return false;
                        }
                    }

                    return true;
                }
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return true;
        }

        virtual const char * GetName()
        {
            return "車";
        }
    };

    //马Horse
    class Horse: public ChinesePiece
    {
    public:
        Horse(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            Point run[8] = {{-2, 1}, {-2, -1}, {-1, 2}, {-1, -2}, {1, 2}, {1, -2}, {2, 1}, {2, -1}},
                norun[8] = {{-1, 0}, {-1, 0}, {0, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 0}, {1, 0}};

            //判断目的地为空或者目的地为对方棋子
            if(board.GetChess(po) == nullptr || board.GetChess(po)->color != this->color)
            {
                for(int i = 0; i < 8; ++i)
                {
                    //按规定走子并且判断是否断马腿
                    if(po == Point(point.x+run[i].x, point.y+run[i].y) && board.GetChess(Point(point.x+norun[i].x, point.y+norun[i].y)) == nullptr)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return true;
        }

        virtual const char * GetName()
        {
            return "馬";
        }
    };

    //炮Cannon
    class Cannon: public ChinesePiece
    {
    public:
        Cannon(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            if(board.GetChess(po) == nullptr)
            {
                //判断中间是否有棋子挡住
                if(po.x == point.x)
                {
                    if(po.y > point.y)
                    {
                        for(int i = po.y-1; i != point.y; --i)
                        {
                            if(board.GetChess(Point(point.x, i)))
                                return false;
                        }
                    }
                    else
                    {
                        for(int i = po.y+1; i != point.y; ++i)
                        {
                            if(board.GetChess(Point(point.x, i)))
                                return false;
                        }
                    }

                    return true;
                }
                else if(po.y == point.y)
                {
                    if(po.x > point.x)
                    {
                        for(int i = po.x-1; i != point.x; --i)
                        {
                            if(board.GetChess(Point(i, point.y)))
                                return false;
                        }
                    }
                    else
                    {
                        for(int i = po.x+1; i != point.x; ++i)
                        {
                            if(board.GetChess(Point(i, point.y)))
                                return false;
                        }
                    }

                    return true;
                }
                return false;
            }
            //吃子
            else if(board.GetChess(po)->color != this->color)
            {
                //判断中间是否有棋子挡住
                if(po.x == point.x)
                {
                    if(po.y > point.y)
                    {
                        for(int i = po.y-1; i != point.y; --i)
                        {
                            if(board.GetChess(Point(point.x, i)))
                                return true;
                        }
                    }
                    else
                    {
                        for(int i = po.y+1; i != point.y; ++i)
                        {
                            if(board.GetChess(Point(point.x, i)))
                                return true;
                        }
                    }

                    return false;
                }
                else if(po.y == point.y)
                {
                    if(po.x > point.x)
                    {
                        for(int i = po.x-1; i != point.x; --i)
                        {
                            if(board.GetChess(Point(i, point.y)))
                                return true;
                        }
                    }
                    else
                    {
                        for(int i = po.x+1; i != point.x; ++i)
                        {
                            if(board.GetChess(Point(i, point.y)))
                                return true;
                        }
                    }

                    return false;
                }
                return false;
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return true;
        }

        virtual const char * GetName()
        {
            return "炮";
        }

    };

    //象Elephant
    class Elephant: public ChinesePiece
    {
    public:
        Elephant(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            Point run[4] = {{2, 2}, {-2, 2}, {-2, -2}, {2, -2}}, norun[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}};

            //判断目的地为空或者目的地为对方棋子
            if(board.GetChess(po) == nullptr || board.GetChess(po)->color != this->color)
            {
                //判断是否在我方区域
                if(this->color == po.ColorOfArea())
                {
                    for(int i = 0; i < 4; ++i)
                    {
                        //按规定走子并且判断是否断马腿
                        if(po == Point(point.x+run[i].x, point.y+run[i].y) && board.GetChess(Point(point.x+norun[i].x, point.y+norun[i].y)) == nullptr)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return false;
        }

        virtual const char * GetName()
        {
            return "象";
        }
    };

    //士Adviser
    class Adviser: public ChinesePiece
    {
    public:
        Adviser(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            Point run[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}};

            //判断目的地为空或者目的地为对方棋子
            if(board.GetChess(po) == nullptr || board.GetChess(po)->color != this->color)
            {
                //判断是否在九宫格中
                if(color == po.ColorOfArea() && po.IsInTheNine())
                {
                    for(int i = 0; i < 4; ++i)
                    {
                        //按规定走子并且判断是否断马腿
                        if(po == Point(point.x+run[i].x, point.y+run[i].y))
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return false;
        }

        virtual const char * GetName()
        {
            return "士";
        }
    };

    //兵Pawn
    class Pawn: public ChinesePiece
    {
    public:
        Pawn(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            //判断目的地为空或者目的地为对方棋子
            if(board.GetChess(po) == nullptr || board.GetChess(po)->color != this->color)
            {
                int goup = po.ColorOfArea() == Red? 1:-1;

                //如果没有过河
                if(po.ColorOfArea() == color)
                {
                    return po == Point(point.x, point.y+goup);
                }
                
                Point run[3] = {{0, goup}, {1, 0}, {-1, 0}};
                for(int i = 0; i < 3; ++i)
                {
                    if(po == Point(point.x+run[i].x, point.y+run[i].y))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return false;
        }

        virtual const char * GetName()
        {
            return "兵";
        }
    };

    //将King
    class King: public ChinesePiece
    {
        friend class ChineseGame;
    public:
        King(const Point &point, bool color, ChineseBoard &chineseboard):ChinesePiece(point, color, chineseboard){}

        virtual bool CanMoveTo(const Point &po)
        {
            Point run[4] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

            //判断目的地为空或者目的地为对方棋子
            if(board.GetChess(po) == nullptr || board.GetChess(po)->color != this->color)
            {
                //判断是否在九宫格中
                if(color == po.ColorOfArea() && po.IsInTheNine())
                {
                    for(int i = 0; i < 4; ++i)
                    {
                        if(po == Point(point.x+run[i].x, point.y+run[i].y))
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        virtual const bool CanCrossRiver()const
        {
            return false;
        }

        virtual const char * GetName()
        {
            return "帅";
        }
    };

    ChineseBoard::ChineseBoard()
    {
        memset(board, 0, sizeof(board));
        new Rook(Point(0, 0), Red, *this);
        new Rook(Point(8, 0), Red, *this);
        new Rook(Point(0, 9), Black, *this);
        new Rook(Point(8, 9), Black, *this);
        new Horse(Point(1, 0), Red, *this);
        new Horse(Point(7, 0), Red, *this);
        new Horse(Point(1, 9), Black, *this);
        new Horse(Point(7, 9), Black, *this);
        new Cannon(Point(1, 2), Red, *this);
        new Cannon(Point(7, 2), Red, *this);
        new Cannon(Point(1, 7), Black, *this);
        new Cannon(Point(7, 7), Black, *this);
        new Elephant(Point(2, 0), Red, *this);
        new Elephant(Point(6, 0), Red, *this);
        new Elephant(Point(2, 9), Black, *this);
        new Elephant(Point(6, 9), Black, *this);
        new Adviser(Point(3, 0), Red, *this);
        new Adviser(Point(5, 0), Red, *this);
        new Adviser(Point(3, 9), Black, *this);
        new Adviser(Point(5, 9), Black, *this);
        new Pawn(Point(0, 3), Red, *this);
        new Pawn(Point(2, 3), Red, *this);
        new Pawn(Point(4, 3), Red, *this);
        new Pawn(Point(6, 3), Red, *this);
        new Pawn(Point(8, 3), Red, *this);
        new Pawn(Point(0, 6), Black, *this);
        new Pawn(Point(2, 6), Black, *this);
        new Pawn(Point(4, 6), Black, *this);
        new Pawn(Point(6, 6), Black, *this);
        new Pawn(Point(8, 6), Black, *this);
        new King(Point(4, 0), Red, *this);
        new King(Point(4, 9), Black, *this);
    }

    ChineseBoard::~ChineseBoard()
    {
        for (ChinesePiece* p : RED)
            delete p;
        for (ChinesePiece* p : BLACK)
            delete p;
    }

    //判断
    bool ChineseBoard::KingFaceToFace()
    {
        auto r = std::find_if(RED.begin(), RED.end(), [](ChinesePiece* p) {return dynamic_cast<King*>(p) != nullptr; }),
            b = std::find_if(BLACK.begin(), BLACK.end(), [](ChinesePiece* p) {return dynamic_cast<King*>(p) != nullptr; });
        if (r != RED.end() && b != BLACK.end())
        {
            if ((*r)->GetPoint().x == (*b)->GetPoint().x)
            {
                for (int i = (*r)->GetPoint().y + 1; i < (*b)->GetPoint().y; i++)
                {
                    if (GetChess(Point((*r)->GetPoint().x, i)))
                        return false;
                }
                return true;
            }
        }
        return false;
    }

    bool isPlayer = Black;

    //游戏类
    class ChineseGame
    {
    private:
        bool nextPlayer;
        ChineseBoard board;
    public:
        ChineseGame():nextPlayer(Red){}

        //获取棋盘
        const ChineseBoard & GetBoard()
        {
            return board;
        }

        bool Move(const Point &a, const Point &b)
        {
            if(board.GetChess(a) && (board.GetChess(a)->color == nextPlayer))
            {
                if(board.GetChess(a)->MoveTo(b))
                {
                    nextPlayer = !nextPlayer;
                    isPlayer = nextPlayer;
                    return true;
                }
                return false;
            }
            return false;
        }

        bool GetNextPlayer()
        {
            return nextPlayer;
        }

        int GetWinner()
        {
            //判断是否将对将
            if(board.KingFaceToFace())
            {
                return nextPlayer;
            }
            //判断将帅是否被吃
            if(find_if(board.GetRedPieces().begin(), board.GetRedPieces().end(), [](ChinesePiece *p){return dynamic_cast<King*>(p) != nullptr;})
                == board.GetRedPieces().end())
                return Black;
            if(find_if(board.GetBlackPieces().begin(), board.GetBlackPieces().end(), [](ChinesePiece *p){return dynamic_cast<King*>(p) != nullptr;})
                == board.GetBlackPieces().end())
                return Red;
            //判断平局
            if(count_if(board.GetRedPieces().begin(), board.GetRedPieces().end(), [](ChinesePiece *p){return (p->CanCrossRiver());}) + 
                count_if(board.GetBlackPieces().begin(), board.GetBlackPieces().end(), [](ChinesePiece *p){return (p->CanCrossRiver());}) == 0)
                return DRAW;
            return CONTINUE;
        }

    };
}